# -*- coding: utf-8 -*-
import os
import os.path
import time
import zipfile

import requests


class ZFile(object):
    """
    文件压缩
    """

    def __init__(self, filename, mode='r', basedir=''):
        self.filename = filename
        self.mode = mode
        if self.mode in ('w', 'a'):
            self.zfile = zipfile.ZipFile(filename, self.mode, compression=zipfile.ZIP_DEFLATED,
                                         allowZip64=True)
        else:
            self.zfile = zipfile.ZipFile(filename, self.mode)
        self.basedir = basedir
        if not self.basedir:
            self.basedir = os.path.dirname(filename)

    def addfile(self, path, arcname=None):
        """
        添加文件
        :param path:
        :param arcname:
        :return:
        """
        path = path.replace('//', '/')
        if arcname is None:
            if path.startswith(self.basedir):
                arcname = path[len(self.basedir):]
            else:
                arcname = ''
        self.zfile.write(path, arcname)

    def addfiles(self, paths):
        """
        添加目录
        :param paths:
        :return:
        """
        for path in paths:
            if isinstance(path, tuple):
                self.addfile(*path)
            else:
                self.addfile(path)

    def close(self):
        """
        关闭
        :return:
        """
        self.zfile.close()

    def extract_to(self, path):
        """
        解压到
        :param path:
        :return:
        """
        for p in self.zfile.namelist():
            self.extract(p, path)

    def extract(self, filename, path):
        """
        解压
        :param filename:
        :param path:
        :return:
        """
        if not filename.endswith('/'):
            f = os.path.join(path, filename)
            dir = os.path.dirname(f)
            if not os.path.exists(dir):
                os.makedirs(dir)
            file(f, 'wb').write(self.zfile.read(filename))


def create_by_path(zfile, paths):
    """
    创建压缩文件 目录集合
    :param zfile:
    :param paths:
    :return:
    """
    z = ZFile(zfile, 'w')
    z.addfiles(paths)
    z.close()


def create_by_files(zfile, files, arcname=None):
    """
    根据文件集创建压缩文件
    :param zfile:
    :param files:
    :param arcname:
    :return:
    """
    z = ZFile(zfile, 'w')
    for f in files:
        if f is not None and len(f) > 0:
            z.addfile(f, arcname)
    z.close()


def extract(zfile, path):
    """
    解压
    :param zfile:
    :param path:
    :return:
    """
    z = ZFile(zfile)
    z.extract_to(path)
    z.close()


def make_dir(path):
    """
    创建文件夹
    :param path:
    :return:
    """
    try:
        os.makedirs(path)
    except Exception as e:
        if str(e).find('File exists') == -1:
            raise e


def download_and_extract(url, out_dir, retry=2):
    """
    下载解压zip文件
    :param url:
    :param out_dir:
    :param retry:
    :return:
    """
    for idx in range(retry + 1):
        try:
            response = requests.get(url)
            filename = response.headers.get('Content-Disposition').split('filename=')[1]
            if not os.path.exists(out_dir):
                make_dir(out_dir)
            zfile = os.path.join(out_dir, filename)
            if os.path.exists(zfile):
                os.remove(zfile)
            with open(zfile, 'wb') as zf:
                zf.write(response.content)
            extract(zfile, out_dir)
            os.remove(zfile)
            return filename
        except Exception as e:
            if idx == retry:
                raise e
            else:
                time.sleep(1)


def download_http_file(url, out_dir, file_name=None, retry=2):
    for idx in range(retry + 1):
        try:
            response = requests.get(url)
            if file_name is None:
                content_dis = response.headers.get('Content-Disposition')
                if content_dis:
                    file_name = content_dis.split('filename=')[1]
            if not os.path.exists(out_dir):
                make_dir(out_dir)
            result_file = os.path.join(out_dir, file_name)
            if os.path.exists(result_file):
                os.remove(result_file)
            with open(result_file, 'wb') as zf:
                zf.write(response.content)
        except Exception as e:
            if idx == retry:
                raise e
            else:
                time.sleep(1)
